home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / GX->PostScript Sample / GXToPostScript / Font Handler / FontHandlerMisc.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  17.1 KB  |  672 lines  |  [TEXT/MPS ]

  1. /*
  2.      File:        FontHandlerMisc.c
  3.  
  4.      Contains:    QuickDraw GX to PostScript conversion code.
  5.  
  6.      Version:    Technology:    Quickdraw GX 1.1.x
  7.       
  8.      Copyright:    © 1991-1997 by Apple Computer, Inc., all rights reserved.
  9. */
  10.  
  11. #include <GXExceptions.h>
  12. #include <MacMemory.h>
  13. #include <Resources.h>
  14. #include <String.h>
  15. #include <TextUtils.h>
  16. #include <Collections.h>
  17. #include "IOUtilities.h"
  18. #include "GXToPSBuildConfig.h"
  19. #include "GXPrintingUniverse.h"
  20. #include "PSProcSetIDs.h"
  21. #include "FontDatabase.h"
  22. #include "FontHandler.h"
  23. #include "FHResources.h"
  24. #include "FontHandlerPrivate.h"
  25. #include "FontHandlerVariations.h"
  26.  
  27. #define noDEBUGFONTSCANTBEUSED
  28.  
  29. /***********************************************
  30.  
  31.     Function: FHSetWorkHandleSize
  32.     
  33.     Function sets the size of the work handle to the 
  34.     requested size and makes it non-purgeable.
  35.     
  36.     The handle is returned in h.
  37.         passing nil indicates that the routine
  38.         is being called to resize from a previous
  39.         SetWorkHandleSize on the indexed handle
  40.         rather than one that is being used as a new allocation.
  41.         This is primarily for debugging purposes.
  42.     
  43.     index is which handle to grow.
  44.     
  45. *************************************************/
  46. OSErr    FHSetWorkHandleSize(TFontHandlerHdl hFHRec, long size, long index, Handle *h)
  47.     {
  48.         OSErr                            status = noErr;
  49.         TFontHandlerPtr        pFHRec;
  50.         Handle                        workHandle;
  51.         long                            currSize;
  52.     
  53.         pFHRec = *hFHRec;
  54.         
  55.         check(index < kMaxWrkSpaces);
  56.  
  57. #if DEBUGLEVEL > 0
  58.         if (pFHRec->workHandleInUse[index] && (h != nil)) {
  59.         
  60.             dprintf(notrace, "Fatal Error, Bug!! WorkHandle %d is already in use!!", index);
  61.             return(-999);
  62.             
  63.         } else {
  64.  
  65.             pFHRec->workHandleInUse[index] = true;
  66.  
  67.         }//end if
  68. #endif
  69.  
  70.         workHandle = pFHRec->workHandle[index];
  71.         HNoPurge(workHandle);
  72.         currSize = pFHRec->workSize[index];
  73.         
  74.         if (*workHandle == 0) {                            // Was it purged?
  75.     
  76.             ReallocateHandle(workHandle, size);
  77.             status = MemError();
  78.             (*hFHRec)->workSize[index] = size;
  79.         
  80.         } else if (currSize < size) {
  81.         
  82.             status = PrSetHandleSize(workHandle, size);
  83.             (*hFHRec)->workSize[index] = size;
  84.             
  85.         }//end if
  86.  
  87.         
  88.         if (h != nil) {
  89.             *h = workHandle;
  90.             //dprintf(trace, "Allocated handle: %d", index);
  91.         }//end if
  92.  
  93.         return(status);
  94.  
  95.     }//FHSetWorkHandleSize
  96.  
  97.  
  98.  
  99. /***********************************************
  100.  
  101.     Function: FHReleaseWorkspace
  102.     
  103.     Function marks the workspace purgeable.
  104.     Call when done with a workspace.
  105.  
  106.     index is which handle to grow.
  107.  
  108. *************************************************/
  109. void FHReleaseWorkspace(TFontHandlerHdl hFHRec, long index)
  110.     {
  111.         Handle h = (*hFHRec)->workHandle[index];
  112.     
  113. #if DEBUGLEVEL > 0
  114.         (*hFHRec)->workHandleInUse[index] = false;
  115. #endif
  116.  
  117.         HUnlock(h);
  118.         HPurge(h);
  119.         
  120.         //dprintf(trace, "released handle: %d", index);
  121.         
  122.     }//FHReleaseWorkspace
  123.  
  124.  
  125. //<FF>
  126. /************************************
  127.  
  128.     Function: CountGlyphBits
  129.     
  130.     Function counts the number of glyphs used
  131.     in a font by counting the 1-bits in the 
  132.     bit array.
  133.     
  134. *************************************/
  135. long    CountGlyphBits(unsigned long* glyphBits, long nGlyphs)
  136.     {
  137.         register unsigned long            mask = 0x80000000;
  138.         register unsigned long            nextLong = *glyphBits;
  139.         long                            i;
  140.         long                             count = 0;
  141.                 
  142.         for (i = 0; i < nGlyphs; ++i) {
  143.             
  144.             if (nextLong & mask)            // check the bit.
  145.                 ++count;
  146.                 
  147.             /** Advance the mask, and check to see if done a longword. **/
  148.             if ( !(mask >>= 1) ) {
  149.             
  150.                 /* If the mask became zero, time to get next longword */
  151.                 
  152.                 mask = 0x80000000;
  153.                 nextLong = *(++glyphBits);
  154.                 
  155.             }//end if
  156.             
  157.         }//end for
  158.         
  159.         return(count);
  160.         
  161.     }//CountGlyphBits
  162.  
  163. //<FF>
  164. /******************************************
  165.  
  166.     Function:    FHGetFontName
  167.     
  168.     This is a wrapper for GXGetFontName.  Does exactly
  169.     the same thing and takes the same parameters.
  170.     
  171.     Additionally, it handles the case where the name index
  172.     for a postscript name is zero in which case it fabricates
  173.     one from the font reference instead of returning nothing.
  174.     
  175.     This allows us to print bogus fonts without postscript names.
  176.  
  177.         If the index is zero, then the font name becomes:
  178.             "GXNoPSName-X" where X is the hex version of the font reference.
  179.  
  180. *******************************************/
  181. long FHGetFontName(gxFont fontID, long index, gxFontName *name, gxFontPlatform *platform,
  182.         gxFontScript *script, gxFontLanguage *language, unsigned char text[])
  183.     {
  184.         long            namelen;
  185.                 
  186.         if (index != kNoSuchFontName) {
  187.  
  188.             /* get the real one */
  189.             
  190.             namelen = GXGetFontName(fontID, index, name, platform, script, language, text);        
  191.         
  192.         } else {
  193.         
  194.             /* Make up a name */
  195.         
  196.             memcpy(text, "GXNoPSName-", 11);
  197.             HexBlockMove((unsigned char*)&fontID, text + 11, sizeof(gxFont) );
  198.             namelen = 11 + 2 * sizeof(gxFont);
  199.             
  200.             #if DEBUGLEVEL > 1
  201.             {
  202.                 unsigned char            theName[255];
  203.                 long            nameSize;
  204.                 nameSize = GXFindFontName(fontID, gxUniqueFontName, gxNoPlatform, gxNoScript, gxNoLanguage, theName, nil);
  205.                 theName[nameSize] = 0x00;
  206.                 dprintf(trace, "font: %s has no valid PostScript name, using: %s", theName, text);
  207.             }        
  208.             #endif
  209.         
  210.         }//end if
  211.         
  212.         check(namelen);
  213.         
  214.         return(namelen);
  215.  
  216.     }//FHGetFontName
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223. //<FF>
  224. /******************************************
  225.  
  226.     Function:        FHGeneratePrinterName
  227.     
  228.     Function generates a printer font name for
  229.     the specified printer font record.
  230.     
  231.     theFont:                    The font reference.
  232.     printerFont:            The printer font record.
  233.     name:                            pointer to a 256 character string.
  234.                                             This will be a null terminated string.
  235.                                             
  236.     returned:                    The length of the string.
  237.  
  238. *******************************************/
  239. long FHGeneratePrinterName(TPrinterFontRec *printerFont, unsigned char name[256])
  240.     {
  241.         long                        nameLen;
  242.         unsigned char        numString[32];
  243.         Boolean                    addSuffix = false;
  244.         Boolean                    nameOfComposite = false;            // make name for synthetic composite font?
  245.         
  246.         /*****
  247.             Determine whether or not to add suffix before calling GetFontName in case mem moves
  248.             Because the printerFont rec may be inside unlocked handle.
  249.             
  250.             Add the printer font index as a suffix to the name; example Chicago$0$1.
  251.             Only do this if the index is greater than zero or the font is a resident font,
  252.             or the dbIndex of the snapshot font is > 0 or we want name of synthetic composite font.
  253.             (We don't want to give a re-encoding of a resident font the same name as the resident font)
  254.             For index 0, just use the PostScript
  255.             name.  This helps apps like FreeHand which depend on the name of the font being the
  256.             PostScript name from the FOND work properly.
  257.             
  258.             dbIndex > 1 forces us to not add a suffix for the first variation snapshot, so that Freehand
  259.             will recognize GX graphics and other variations fonts when printing from QD.
  260.         *****/
  261.         
  262.         if (!(printerFont->info & fontCantBeRencoded))
  263.             if ((printerFont->prFontIndex > 0) || (printerFont->info & fontIsInPrinter) || (printerFont->dbIndex > 1))
  264.                 addSuffix = true; 
  265.             
  266.         nameLen = FHGetFontName(printerFont->theRealFont, printerFont->nameIndex, nil, nil, nil, nil, name);
  267.         
  268.         
  269.         if (addSuffix) {
  270.         
  271.             /** Add the snapshot index into the name **/
  272.             
  273.             name[nameLen++] = '$';
  274.             NumToString((long)(printerFont->dbIndex), numString);
  275.             memcpy(name + nameLen, &numString[1], numString[0]);
  276.             nameLen += numString[0];
  277.             
  278.  
  279.             /** Add the printer font index to the name **/
  280.             
  281.             name[nameLen++] = '$';
  282.             NumToString(printerFont->prFontIndex, numString);
  283.             memcpy(name + nameLen, &numString[1], numString[0]);
  284.             nameLen += numString[0];
  285.             
  286.         }//end if
  287.         
  288.         /** Add a null byte to end to make it a C friendly string, but don't increment length byte **/
  289.         
  290.         name[nameLen] = 0;
  291.  
  292.         return(nameLen);
  293.         
  294.     }//FHGeneratePrinterName
  295.  
  296.  
  297.  
  298.  
  299. //<FF>
  300. /***************************************
  301.  
  302.     Function: FHGetStylePrFontIndex
  303.     
  304.     function returns the printer font index
  305.     associated with a style
  306.     
  307. ****************************************/
  308. long FHGetStylePrFontIndex(gxStyle theStyle)
  309.     {
  310.         gxTag             fontIndexTag;
  311.         long                index;
  312.         
  313.         GXGetStyleTags(theStyle, prFontIndexTag, 1, 1, &fontIndexTag);
  314.         GXGetTag(fontIndexTag, nil, &index);
  315.  
  316.         ncheck(GXGetGraphicsError(nil));
  317.         return(index);
  318.     
  319.     }//FHGetStylePrFontIndex
  320.  
  321.  
  322. //<FF>
  323. /**************************************
  324.  
  325.     Wrapper for GXGetStyleFont.
  326.     Makes sure that we never get nil.
  327.  
  328. ***************************************/
  329. gxFont FHgxGetStyleFont(gxStyle theStyle)
  330.     {
  331.         gxFont theFont = GXGetStyleFont(theStyle);
  332.         if (theFont == nil)
  333.             theFont = GXGetDefaultFont();
  334.             
  335.         return(theFont);
  336.     }
  337.  
  338.  
  339.  
  340. //<FF>
  341. /******************************************
  342.  
  343.     Function:    FHFontMayBe2Byte
  344.     
  345.     Function tests to see if a font supports a 2 byte
  346.     script.
  347.     
  348. *******************************************/
  349. Boolean    FHFontMayBe2Byte(gxFont theFont)
  350.     {
  351.         long                            encodingCount;
  352.         long                            i;
  353.         gxFontPlatform        thePlatform;
  354.         gxFontScript            theScript;
  355.         
  356.         encodingCount = GXCountFontEncodings(theFont);
  357.         
  358.         for (i = 1; i <= encodingCount; ++i) {
  359.  
  360.             thePlatform = GXGetFontEncoding(theFont, i, &theScript, nil);
  361.             
  362.             if ( (theScript == gxJapaneseScript) ||
  363.                      (theScript == gxTraditionalChineseScript) ||
  364.                      (theScript == gxChineseScript) ||
  365.                      (theScript == gxKoreanScript) ) {
  366.                      
  367.                 return(true);
  368.                 
  369.             }//end if
  370.     
  371.         }//end for
  372.     
  373.         return(false);
  374.     
  375.     }//FHFontMayBe2Byte
  376.  
  377. //<FF>
  378. /**********************************
  379.  
  380.     Routine tests to see if a font requires
  381.     snapshots or not to do variations given
  382.     the set of legal stream types.  We can also
  383.     find out from this call if a font can be
  384.     streamed at all.
  385.     
  386.     We us the variationQueryStreamAction to find
  387.     out both at the same time.
  388.     
  389.     theFont:                        The font in question
  390.     psDevice:                        A pointer to a device object.
  391.     legalStreamTypes:        The allowable streaming types for the target device.
  392.     productDescription:    The product description string.
  393.     requirements:                Code indicating stream requirements for the font.
  394.     
  395. ***********************************/
  396. OSErr FHGetStreamRequirements(gxFont theFont, CGXtoPostScriptDevice *psDevice, scalerStreamTypeFlag legalStreamTypes, 
  397.                                                             char *productDescription, TFHStreamRequirements *requirements)
  398.     {
  399.         OSErr                            status;
  400.         scalerStream            streamRecord;
  401.         
  402.         streamRecord.types = legalStreamTypes;
  403.         streamRecord.targetVersion = productDescription;
  404.         streamRecord.action = variationQueryStreamAction;
  405.         streamRecord.variationCount = selectAllVariations;
  406.         streamRecord.variations = nil;
  407.         
  408.         status = psDevice->StreamFont(theFont, &streamRecord);
  409.  
  410.         if (status == unsupported_font_scaler_stream_format) {
  411.  
  412.             /* This is not an abort case, just note font can't be streamed */
  413.             
  414.             status = noErr;
  415.             *requirements = fhCantStreamFont;
  416.             
  417.             #if DEBUGLEVEL > 0
  418.                 dprintf(trace, "Font %X can't be streamed", theFont);
  419.             #endif
  420.  
  421.         } else { 
  422.  
  423.             nrequire(status, failed_stream);
  424.             
  425.             /* If there was no error, find out if there is a snapshot requirement */
  426.  
  427.             if (streamRecord.info.variationQueryResult & 0x00000001)
  428.                 *requirements = fhNeedsSnapShots;
  429.             else
  430.                 *requirements = fhNormalStreaming;
  431.             
  432.         }//end if
  433.  
  434. failed_stream:        
  435.         return(status);
  436.  
  437.     }//FHGetStreamRequirements
  438.  
  439.  
  440. //<FF>
  441. /******************************************
  442.  
  443.     Function: FHTestFontCanBeUsed
  444.  
  445.     Function looks at a font and decides whether
  446.     or not the font can be used at all (answer
  447.     no means the font handler client (Imaging Engine for example)
  448.     mush do something other than using the printer font
  449.     (downloaded or resident) to render the glyphs (such as host rasterization).
  450.          
  451.      hFHRec:                    Font handler context handle.
  452.      theFont:                    fhFont reference.
  453.      glyphsUsed:            Total number of glyphs used by the document
  454.      glyphsEncoded:        Total number of glyphs encoded for printer resident font.
  455.      
  456. ******************************************/
  457. OSErr FHTestFontCanBeUsed(TFontHandlerHdl hFHRec, fhFont theFont, long glyphsUsed, long glyphsEncoded, Boolean *canUseFont)
  458.     {
  459.         OSErr                                    status = noErr;
  460.         gxFont                                theRealFont;                        // the actual gx font reference implied by the fhFont value.
  461.         TFHStreamRequirements    requirements;                        // Stream Requirements for this font.
  462.         
  463.  
  464.         *canUseFont = true;
  465.         
  466.         theRealFont = FHGetSnapShotFont(hFHRec, theFont, nil);
  467.         check(theRealFont);
  468.         
  469.         /* If we need to download any glyphs and it is a Morisawa font, return false - they don't stream */
  470.                 
  471.         if ( (glyphsUsed - glyphsEncoded) > 0  ) {
  472.         
  473.             /* Streaming may not be allowed by scaler for this font */
  474.             
  475.             status = FHGetStreamRequirements( theRealFont, (*hFHRec)->psDevice, (*hFHRec)->legalStreamTypes, 
  476.                                                                                 (*hFHRec)->productDescription, &requirements);
  477.                                                                                 
  478.             nrequire(status, failed_getRequirements);
  479.  
  480.             if ( requirements == fhCantStreamFont ) {
  481.             
  482.                 *canUseFont = false;
  483.                     
  484.                 #if DEBUGLEVEL > 1
  485.                 dprintf(trace, "Can't download Font font, Client should do Bitmaps or paths");
  486.                 #endif
  487.                 
  488.             }//end if            
  489.                 
  490.         } else if ( (*hFHRec)->printerCanDoAllFonts || ( (glyphsUsed - glyphsEncoded) <= 256) ) {
  491.         
  492.             /** If we need to dowload 256 or fewer glyphs or printer doesn't care, return true **/
  493.  
  494.             #ifdef DEBUGFONTSCANTBEUSED
  495.                 char            theName[255];
  496.                 long            nameSize;
  497.                 theRealFont = FHGetSnapShotFont(hFHRec, theFont, nil);
  498.                 nameSize = GXFindFontName(theRealFont, gxUniqueFontName, gxNoPlatform, gxNoScript, gxNoLanguage, theName, nil);
  499.                 theName[nameSize] = 0x00;
  500.                 if (glyphsUsed - glyphsEncoded > 0)
  501.                     dprintf(trace, "Font %s will be downloaded!, #glyphs required: %d", theName, glyphsUsed - glyphsEncoded);
  502.                 else
  503.                     dprintf(trace, "Font on printer %s will be used!", theName);
  504.         
  505.             #endif
  506.             
  507.             *canUseFont = true;
  508.                         
  509.         } else {
  510.         
  511.             /** If the font is a two byte font and we need to download more than 256 glyphs, set return false **/
  512.                     
  513.             if ( FHFontMayBe2Byte(theRealFont) ) {
  514.             
  515.                 #ifdef DEBUGFONTSCANTBEUSED
  516.                 char            theName[255];
  517.                 long            nameSize;
  518.                 nameSize = GXFindFontName(theRealFont, gxUniqueFontName, gxNoPlatform, gxNoScript, gxNoLanguage, theName, nil);
  519.                 theName[nameSize] = 0x00;
  520.                 dprintf(trace, "Font %s cannot be used!, #glyphs required: %d", theName, glyphsUsed - glyphsEncoded);
  521.                 #endif
  522.                 
  523.                 *canUseFont = false;
  524.             
  525.             }//end if
  526.                     
  527.         }//end if
  528.  
  529. failed_getRequirements:
  530.  
  531.         return(status);
  532.                 
  533.     }//FHTestFontCanBeUsed
  534.  
  535.  
  536.  
  537. /*******************************
  538.  
  539.     Function decides based on product
  540.     name whether or not the printer can 
  541.     handle all font downloading.  If it can't
  542.     then this implies that shapes with certain
  543.     fonts will cause ResolveShapeFonts to return
  544.     the outline_font_not_found error - implying 
  545.     that the client should take other action.
  546.     
  547.     productName:            pascal string for product name.
  548.     printerCan:                (returned) can the printer handle all downlaoded fonts.
  549.     
  550. **********************************/
  551. OSErr    FHCanPrinterHandleAllFonts(unsigned char *productName, Boolean *printerCan)
  552.     {
  553.         OSErr                            status = noErr;
  554.         Handle                        printerNames;
  555.         unsigned char            *name;
  556.         short                            nameCount, counter;
  557.  
  558.         *printerCan = true;    
  559.  
  560.         printerNames = GetResource('STR#', kFHPrintersThatCantDoAllFonts);
  561.         require(printerNames, failed_getnames);
  562.  
  563.         /** Traverse all of the names in the resource, search for match **/
  564.         
  565.         name = (unsigned char*)*printerNames;
  566.         nameCount = *((short*)name);
  567.         name += 2;
  568.         
  569.         for (counter = 0; counter < nameCount; ++counter) {
  570.             
  571.             if (productName[0] == name[0]    ) {
  572.  
  573.                 if ( memcmp( productName + 1, name + 1, productName[0]) == 0 ) {
  574.                     
  575.                     #ifdef DEBUGFONTSCANTBEUSED
  576.                     dprintf(trace, "Printer can't do all fonts: %s", productName + 1);
  577.                     #endif
  578.                     
  579.                     *printerCan = false;
  580.                     break;
  581.                     
  582.                 }//end if
  583.                                 
  584.             }//end if
  585.             
  586.             name += name[0] + 1;            // point to the next string in the resource.
  587.         
  588.         }//end for
  589.         
  590.     
  591.         return(status);
  592.         
  593. failed_getnames:
  594.         status = MemError();
  595.         if (status == noErr)
  596.             status = ResError();
  597.     
  598.         return(status);
  599.     
  600.     }//FHCanPrinterHandleAllFonts
  601.  
  602.  
  603.  
  604.  
  605.  
  606. /***************** Utility routines *******************/
  607.  
  608.  
  609. /**************************
  610.  
  611.         Function: FHCountPrinterFonts
  612.         
  613.         Returns the number of printer fonts for a document font.
  614.  
  615. ***************************/
  616. long        FHCountPrinterFonts(TFontHandlerHdl hFHRec, fhFont theFont)
  617.     {
  618.         long            nPrFonts;
  619.         
  620.         nPrFonts = CountTaggedCollectionItems((*hFHRec)->printerFontsOffsets, (CollectionTag)theFont);            
  621.  
  622.         return(nPrFonts);
  623.     
  624.     }//FHCountPrinterFonts
  625.  
  626.  
  627.  
  628. /**************************
  629.  
  630.         Function: FHGetIndexedPrinterFont
  631.         
  632.         Returns the Pointer to a printer font record for a document font.
  633.  
  634.         hFHRec:                pointer to the font handler context.  (Note, returned printer font pointer is only valid if handle does't move)
  635.         theFont:            The Document font in question.
  636.         index:                Index of the desired printer font.
  637.         printerFont:    (returned) pointer to the printer font record.
  638.         theOffset:        offset into printer font list so printerFont can be recomputed if handle moves.
  639.  
  640. ***************************/
  641. OSErr FHGetIndexedPrinterFont(TFontHandlerHdl hFHRec, fhFont theFont, long index, TPrinterFontRec* *printerFont, long *theOffset)
  642.     {
  643.         OSErr        status;    
  644.         long        offset;
  645.  
  646.         /** For a two byte group member, return the zero'th printer font **/
  647.         
  648.         if (index == kTwoByteGroupIndex)
  649.             index = 0;
  650.  
  651.         *printerFont = nil;    
  652.         status = GetCollectionItem((*hFHRec)->printerFontsOffsets,
  653.                                                              (CollectionTag)theFont,
  654.                                                              index,
  655.                                                              nil,
  656.                                                              &offset);
  657.         nrequire(status, failed_GetItem);
  658.         
  659.         *printerFont = (TPrinterFontRec*)((*hFHRec)->printerFonts + offset);
  660.         
  661.         if (theOffset != nil)
  662.             *theOffset = offset;
  663.     
  664. failed_GetItem:
  665.  
  666.         return(status);
  667.     
  668.     }//FHGetIndexedPrinterFont
  669.  
  670.  
  671.  
  672.